package com.sunseaypw.db.trans;

import java.sql.DriverManager;

import javax.sql.DataSource;

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

public class DbTrans {
    public static void main(String[] args){
        //jdbcTransBase();
        //springTxmanager();
        //springTxmanager2();
    }
    public static void springTxmanager2(){
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:mysql://192.168.1.135:3306/TEST?useSSL=false&characterEncoding=utf8&allowMultiQueries=true");
        config.setUsername("root");
        config.setPassword("770619");
        config.addDataSourceProperty("autoCommit", "true");
        config.addDataSourceProperty("connectionTimeout", "5");
        config.addDataSourceProperty("idleTimeout", "60");
        config.addDataSourceProperty("maximumPoolSize", "10"); // 最大连接数：10
        var ds =new HikariDataSource(config);
        DataSourceTransactionManager ptm=new DataSourceTransactionManager();
        ptm.setDataSource(ds);
        var td=new DefaultTransactionDefinition(); 
        td.setIsolationLevel(DefaultTransactionDefinition.ISOLATION_DEFAULT);
        td.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRED);
        TransactionStatus ts = ptm.getTransaction(td);
        try{  
            /* jdbcTemplate也是通过DataSourceUtils去拿这个holder里面的connection的
                也就是说 将事务相关对象持久化到ThreadLocal中是一种约定，Map的键key一般为dataSource的名称
                TransactionStatus中持有一个对应的连接对象（可能是新建的或者是嵌套下来的）
            */    
            var jt=new JdbcTemplate(ds);           
            jt.execute("update students set name='第111111111111111次更新' where id=8 ");
            jt.execute("update students set name2222='第222222222222222次更新' where id=8 ");
            ptm.commit(ts);
        }catch(Exception ex){
            ptm.rollback(ts);
            System.out.println("rollback for ::"+ex.getMessage());
        }

    }    
    public static void springTxmanager(){
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:mysql://192.168.1.135:3306/TEST?useSSL=false&characterEncoding=utf8&allowMultiQueries=true");
        config.setUsername("root");
        config.setPassword("770619");
        config.addDataSourceProperty("autoCommit", "true");
        config.addDataSourceProperty("connectionTimeout", "5");
        config.addDataSourceProperty("idleTimeout", "60");
        config.addDataSourceProperty("maximumPoolSize", "10"); // 最大连接数：10
        var ds =new HikariDataSource(config);
        DataSourceTransactionManager ptm=new DataSourceTransactionManager();
        ptm.setDataSource(ds);
        var td=new DefaultTransactionDefinition(); 
        td.setIsolationLevel(DefaultTransactionDefinition.ISOLATION_DEFAULT);
        td.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRED);
        TransactionStatus ts = ptm.getTransaction(td);
        try{  
            /* 必须用DataSourceUtils.doGetConnection获取连接，才能将事务管理器中的打入当前线程ThreadLocal中的对象取出
                jdbcTemplate也是通过DataSourceUtils去拿这个holder里面的connection的
                也就是说 将事务相关对象持久化到ThreadLocal中是一种约定，Map的键key一般为dataSource的名称
                TransactionStatus中持有一个对应的连接对象（可能是新建的或者是嵌套下来的）
            */               
            var con=DataSourceUtils.doGetConnection(ds);
            //var con=ptm.getDataSource().getConnection();
            try(var ps=con.prepareStatement("update students set name='第一次修正11111111111' where id=7")){
                if(1 !=ps.executeUpdate()){
                    throw new RuntimeException("第一次修正没有修改成功啊！");
                }
            }
            try(var ps=con.prepareStatement("update students set name111='第二次修正22222222222' where id=7")){
                if(1 !=ps.executeUpdate()){
                    throw new RuntimeException("第二次修正没有修改成功啊！");
                }
            }
            ptm.commit(ts);
        }catch(Exception ex){
            ptm.rollback(ts);
            System.out.println("rollback for ::"+ex.getMessage());
        }

    }
    public static void jdbcTransBase(){
        try{
            var con=DriverManager.getConnection("jdbc:mysql://192.168.1.135:3306/TEST?useSSL=false&characterEncoding=utf8&allowMultiQueries=true","root","770619");
            try{
                /*jdbc事务就是将默认的每语句式的自动提交关闭，而采用批量语句后再批量提交模式！
                  因为很繁琐，所以有了spring的事务体系，当然spring事务体系是涵盖分布式环境下的两阶段提交场景的！！
                  另外spring事务体系下还包括嵌套事务即事务在代码逻辑链中传播体系模式！
                */
                con.setAutoCommit(false);
                try(var ps=con.prepareStatement("select * from students where id=7")){
                    try(var rs=ps.executeQuery()){
                        if(rs.next()){
                            System.out.println("修改前的："+rs.getString("name"));
                        }
                    }
                }
                /*事务内多条sql语句，写起来非常繁琐，所以有了jdbcTemplate
                */
                try(var ps=con.prepareStatement("update students set name='修正后的小强' where id=7")){
                    if(1 !=ps.executeUpdate()){
                        throw new RuntimeException("没有修改成功啊！");
                    }
                }
                try(var ps=con.prepareStatement("select * from students where id=7")){
                    try(var rs=ps.executeQuery()){
                        if(rs.next()){
                            System.out.println("修改后的："+rs.getString("name"));
                        }
                    }
                }
                con.commit();
            }catch(Exception ex){
                con.rollback();
                System.out.println("rollback because:::"+ex);
            }finally{
                con.setAutoCommit(true);
                con.close();
            }
        }catch(Exception ex){
            System.out.println(ex);
        }
    }
}
